const app = getApp();
const DOMAIN_JST = 'jst-app-master.oss-cn-zhangjiakou.aliyuncs.com'
const COLLECTION_FILE_ID_MAPPING = 'pfFileIdMapping'
const COLLECTION_MAKEUP_PRODUCTS = 'pfMkProducts'
const COLLECTION_PRE_PROCESS_DATA = 'pfMkPreProcessData'
const COLLECTION_IDC = 'pfIDC'
const COLLECTION_LOOKS = 'pfMkLooks'

// keys for matching url in json
const KEY_PRE_PROCESS_DATA = ['texture']
const KEY_MAKEUP_PRODUCTS = ['attr_path', 'attr_thumbnail', 'attr_imagesrc']
const KEY_IDC = ['thumbnail', 'src']
const KEY_LOOKS = ['thumbnailURL']

const what = Object.prototype.toString;

// Set DEBUG to false can change content of original collection
const DEBUG = true

Page({
  data: {
    log:''
  },
  onLoad() {
    self = this
  },
  onShow() {
    this.log('cloudEnv:' + app.globalData.debugSetting.cloudEnv)
  },

  log(msg) {
    this.setData({
      log: this.data.log + '\n[LOG]' + msg
    })
  },

  onUploadLook() {
    my.confirm({
      title: '温馨提示',
      content: '此動作將會覆蓋' + app.globalData.debugSetting.cloudEnv + '雲數據庫:' + COLLECTION_LOOKS + '\n確定執行?',
      success: (result) => {
        if (result.confirm) {
          this.parseAndReUploadLoadImage(COLLECTION_LOOKS, KEY_LOOKS)
        }
      },
    });
  },

  onUploadIDC() {
    my.confirm({
      title: '温馨提示',
      content: '此動作將會覆蓋' + app.globalData.debugSetting.cloudEnv + '雲數據庫:' + COLLECTION_IDC + '\n確定執行?',
      success: (result) => {
        if (result.confirm) {
          this.parseAndReUploadLoadImage(COLLECTION_IDC, KEY_IDC)
        }
      },
    });
  },

  onUploadPreProcessData() {
    my.confirm({
      title: '温馨提示',
      content: '此動作將會覆蓋' + app.globalData.debugSetting.cloudEnv + '雲數據庫:' + COLLECTION_PRE_PROCESS_DATA + '\n確定執行?',
      success: (result) => {
        if (result.confirm) {
          this.parseAndReUploadLoadImage(COLLECTION_PRE_PROCESS_DATA, KEY_PRE_PROCESS_DATA)
        }
      },
    });
  },

  onUploadMakeupProducts() {
    my.confirm({
      title: '温馨提示',
      content: '此動作將會覆蓋' + app.globalData.debugSetting.cloudEnv + '雲數據庫:' + COLLECTION_MAKEUP_PRODUCTS + '\n確定執行?',
      success: (result) => {
        if (result.confirm) {
          this.parseAndReUploadLoadImage(COLLECTION_MAKEUP_PRODUCTS, KEY_MAKEUP_PRODUCTS)
        }
      },
    });
  },

  async deleteLegacyFiles(key) {
    await app.cloud.db.createCollection(COLLECTION_FILE_ID_MAPPING)
    let result = await app.cloud.db.collection(COLLECTION_FILE_ID_MAPPING).find()
    if (result.length <= 0) {
      this.log('Canot find legacy files')
      return
    }

    const fileIds = result[0][key]
    if (!fileIds) {
      this.log('Canot find legacy files')
      return
    }

    let index = 1
    const length = fileIds.length
    for (const element of fileIds) {
      this.log('Delete file start (' + index + '/' + length + ')')
      await this.delete(element.fileId)
      this.log('Delete file success (' + index + '/' + length + ')')
      index++
    }
  },

  async parseAndReUploadLoadImage(collectionName, findingKeys) {
    my.showLoading()
    try {
      await this.deleteLegacyFiles(collectionName)
      let newRecords = []
      let uploadedFileIds = []
      let records = await app.cloud.db.collection(collectionName).find({ _id: { $type: 'string' } })
      const length = records.length
      let index = 1
      for (const element of records) {
        this.log('Traverse record start (' + index + '/' + length + ')')
        await this.traverseJsonObj(element, this.checkAndReplaceUrl, collectionName, findingKeys, uploadedFileIds)
        newRecords.push(element)
        this.log('Traverse record success (' + index + '/' + length + ')')
        index++
      }
      this.log('Upload all file complete, total ' + uploadedFileIds.length + ' files')
      await this.updateFileIds(collectionName, uploadedFileIds)
      await this.updateCollection(DEBUG ? collectionName+'Backup' : collectionName, newRecords)
      my.hideLoading()
    } catch (e) {
      this.log('error:' + JSON.stringify(e))
      my.hideLoading()
    }
  },

  async updateCollection(collectionName, list) {
    this.log('update collection ' + collectionName + ' start')
    await app.cloud.db.createCollection(collectionName)
    const collection = await app.cloud.db.collection(collectionName);
    await this.clearCollection(collection);
    await collection.insertMany(list);
    this.log('update collection ' + collectionName +' success, total ' + list.length + ' records')
  },

  async updateFileIds(key, fileIds) {
    this.log('update collection ' + COLLECTION_FILE_ID_MAPPING + ' start')
    await app.cloud.db.createCollection(COLLECTION_FILE_ID_MAPPING)
    const collection = await app.cloud.db.collection(COLLECTION_FILE_ID_MAPPING)
    let result = await collection.find()
    if (result.length == 0) {
      await collection.insertOne({
        [key]: fileIds
      })
    } else {
      await collection.updateMany({
        _id: { $ne: 0 }
      }, {
        $set: { [key]: fileIds }
      })
    }
    this.log('update collection ' + COLLECTION_FILE_ID_MAPPING + ' success, total ' + fileIds.length + ' files')
  },

  parseUrl(url) {
    var match = url.match(/^(https?\:)\/\/(([^:\/?#]*)(?:\:([0-9]+))?)([\/]{0,1}[^?#]*)(\?[^#]*|)(#.*|)$/);
    return match && {
      url: url,
      protocol: match[1],
      host: match[2],
      hostname: match[3],
      port: match[4],
      pathname: match[5],
      search: match[6],
      hash: match[7]
    }
  },

  replaceDomain(url) {
    const tempUrl = self.parseUrl(url)
    const newUrl = url.replace(tempUrl.host, DOMAIN_JST)
    return newUrl
  },

  async delete(fileId) {
    let result;
    try {
      result = await app.cloud.file.deleteFile({ fileId })
    } catch (e) {
      self.log('Delete failed: ' + JSON.stringify(e))
    }
    return result
  },

  download(url) {
    return new Promise((resolve, reject) => {
      my.downloadFile({
        url: url,
        success: (result) => {
          resolve(result.apFilePath)
        },
        fail: (res) => {
          my.alert({
            content: 'download ' + url + ' error=' + JSON.stringify(res)
          })
          reject(res)
        }
      })
    })
  },

  upload(folder, localFilePath) {
    const name = Date.now()
    return app.cloud.file.uploadFile({  
      filePath: localFilePath,
      fileType: 'image',  
      fileName: '/reupload/' + folder+'/' + name
    }).catch(e => {
      my.alert({
        content: 'upload ' + localFilePath + ' error=' + JSON.stringify(e)
      })
    })
  },

  clearCollection(collection) {
    return collection.deleteMany({
      _id: { $type: 'string' }
    });
  },

  async traverseJsonObj(obj, fn, collectionName, findingKeys, uploadedFileIds) {
    const objString = what.call(obj);
    if (objString == "[object Object]") {
      for (const key of Object.keys(obj)) {
        await fn(obj, key, collectionName, findingKeys, uploadedFileIds);
        const item = obj[key], itemString = what.call(item);
        if (itemString == "[object Object]" || itemString == "[object Array]") {
          await self.traverseJsonObj(item, fn,  collectionName, findingKeys, uploadedFileIds);
        }
      }
    } else if (objString == "[object Array]") {
      for (const item of obj) {
        const itemString = what.call(item);
        if (itemString == "[object Object]" || itemString == "[object Array]") {
          await self.traverseJsonObj(item, fn, collectionName, findingKeys, uploadedFileIds);
        }
      }
    } else {
      throw new Error("unsupported object type")
    }
  },

  async checkAndReplaceUrl(parent, key, collectionName, findingKeys, uploadedFileIds) {
    const value = parent[key]
    if (!value || !findingKeys.includes(key)) {
      return
    }

    if ((value.toString().startsWith('http://')) || value.toString().startsWith('https://')) {
      self.log('re-upload file start, source url: ' + value)
      let jstUrl = self.replaceDomain(value)
      const filePath = await self.download(jstUrl)
      const result = await self.upload(collectionName, filePath)
      parent[key] = result.url;
      uploadedFileIds.push({
        url: result.url,
        fileId: result.fileId,
        jstUrl: jstUrl
      })
      self.log('re-upload file success, final url: ' + result.url)
    }
  },
});